home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / General App Samples / QDGX Scrolling ƒ / QDGX Scrolling main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-20  |  40.1 KB  |  1,363 lines  |  [TEXT/MMCC]

  1. /**
  2.  --        App:        QuickDraw GX Scrolling
  3.  --
  4.  --        File:        GX Scrolling (main).c 
  5.  --
  6.  --        Comments:    This code demonstrates scrolling of a window containing GX shapes. I create
  7.  --                    a window in the CreateDocumentWindow function. At this point, I attach a 
  8.  --                    parent viewPort to the window, and a child viewPort to the parent. This 
  9.  --                    approach enables our application to accommodiate scroll bars and adjust
  10.  --                    the child viewPort's gxMapping to reflect scrolling of the window's contents.
  11.  --
  12.  --                    You might be wondering, why not just perform the same actions on the parent
  13.  --                    viewPort attached to the window? You cannot manipulate the viewPort attached
  14.  --                    to the window. All of it's attributes are maintained by the GX system. This
  15.  --                    leads to a clipping problems because scroll bars are not really part of the
  16.  --                    window's definition.
  17.  --
  18.  --                    Therefore, we attach the child viewPort to set it's clip shape within the
  19.  --                    scroll bars. Also, we update the mapping of this viewPort when the user scrolls,
  20.  --                    thereby guaranteeing that all of the shapes are re-drawn in their correct location.
  21.  --                    Another approach, would be to update the location of each shape contained in the 
  22.  --                    window after scrolling. This would require a lot of work on the application's part. 
  23.  --                    You would also need to undo this operation at print time because your shapes 
  24.  --                    would not reside in their correct location relative to a page.
  25.  --
  26.  --                    If you are interested in finding the GX additions required to run on a GX
  27.  --                    system, search for "GX Additions". If you are only interested in the additions
  28.  --                    required to support scrolling in a GX world, search on "GX Scrolling". 
  29.  --
  30.  --                    The file titled: "GX Scrolling Controls.c" contains of the code required to 
  31.  --                    maintain, draw, and update the scroll bars.
  32.  --
  33.  --
  34.  --        Version:    1.0     1/93    added general GX support & scrolling
  35.  --                            7/95    Converted to ThinkC 6 and new GX interfaces
  36.  --
  37.  --
  38.  --        Components:    QDGX Scrolling main.c
  39.  --                    QDGX Scrolling main.h
  40.  --                    QDGX Scrolling Controls.c
  41.  --                    QDGX Scrolling Controls.h
  42.  --                    QDGX Scrolling.π.rsrc
  43.  --
  44.  --
  45.  --        Bugs:        If you zoom the window onto a montior which is bigger than the default, you
  46.  --                    will receive a GRAPHICS WARNING about how the gxPoint does not intersect the 
  47.  --                    current gxViewPort. From that gxPoint on, until you resize the window to a smaller
  48.  --                    size scrolling will not work correctly. You can create this problem by zooming
  49.  --                    from an Apple 16" monitor to a portrait monitor.
  50.  --                    
  51.  --                    I'm currently working on resolving this problem.
  52.  --
  53.  --
  54.  --        Notes:        1) Print this file in landscape for the best results
  55.  --                    2) If you are using THINK C v5.x, I have added THINK markers to navigate the code.
  56.  --                    3) This code was adapted and simplyified from the "DTS AE Skeleton" sample.
  57.  --
  58.  --
  59.  --        Future
  60.  --        Additions:    1) This code should check to make sure it is running under System 7.1 and the
  61.  --                       GX system is installed.
  62.  --
  63.  --
  64.  --        Author:        Pete "Luke" Alexander
  65.  --                    Developer Technical Support
  66.  --                    AppleLink: DEVSUPPORT
  67.  --
  68.  --        
  69.  --        ©1992 - 1993  Apple Computer, Inc. 
  70.  --        All rights reserved.
  71.  --
  72.  **/
  73.  
  74. #include <AppleEvents.h>
  75. #include <Desk.h>
  76. #include <Dialogs.h>
  77. #include <DiskInit.h>
  78. #include <Errors.h>
  79. #include <Fonts.h>
  80. #include <GestaltEqu.h>
  81. #include <Menus.h>
  82. #include <Memory.h>
  83. #include <OSEvents.h>
  84. #include <OSUtils.h>
  85. #include <Quickdraw.h>
  86. #include <Resources.h>
  87. #include <SegLoad.h>
  88. #include <Script.h>
  89. #include <StandardFile.h>
  90. #include <ToolUtils.h>
  91. #include <Windows.h>
  92.  
  93. #include "QDGX Scrolling main.h"
  94. #include "QDGX Scrolling Controls.h"
  95.  
  96. #include <GXEnvironment.h>
  97. #include <GXGraphics.h>
  98. #include <GXErrors.h>
  99. #include "GraphicsLibraries.h"
  100.  
  101.  
  102. //
  103. // Prototypes
  104. //
  105. void HandleEvent(void);
  106. void HandleMouseDown(EventRecord *theEvent);
  107. void HandleKeyPress(EventRecord *theEvent);
  108. void HandleDiskEvent(EventRecord *theEvent);
  109. void HandleOSEvent(EventRecord *theEvent);
  110.  
  111. void DoGrowWindow(WindowPtr theWindow, Point where);
  112. void DoZoomWindow(WindowPtr theWindow, short thePart);
  113. void ActivateWindow(WindowPtr theWindow, Boolean activate);
  114. void FitWindowOnDevice(Rect *windRect, Rect *deviceRect);
  115. Rect GetDeviceRect(WindowPtr theWindow);
  116.  
  117. void DoMenu(long menuChoice);
  118. void DoOpenCommand(void);
  119. void DoPrintCommand(void);
  120. void PrintDocument(PicHandle thePicture);
  121.  
  122. PicHandle ReadDocument(FSSpecPtr mySpec);
  123. Boolean CreateDocumentWindow(PicHandle thePicture, Str63 name);
  124. void CloseFrontWindow(void);
  125. void DrawWindow(WindowPtr theWindow);
  126. void AdjustMenus(void);
  127.  
  128. void ToolBoxInit(void);
  129. void MenuBarInit(void);
  130. void PrintInit(void);
  131. Boolean ColorQDAvail(void);
  132. Boolean FileRoutinesAvail(void);
  133. void ErrorAlert(short errNumber, Boolean fatal);
  134. void ShutdownProgram(void);
  135.  
  136. //
  137. // The following functions were added to support GX, and add scrolling window support.
  138. //
  139. void QuickDrawGXInit(void);
  140. void GetWindowBoundsShape(WindowPtr myWindow, gxRectangle *boundingBoxPtr);
  141. gxShape CreateThePageOfGXShapes (gxShape thePage);
  142. void ResetContentViewPortClip (WindowPtr theWindow);
  143.  
  144.  
  145. //
  146. // Global Variables
  147. //
  148. Boolean                gDone;            /* Has the user selected quit? */
  149. gxGraphicsClient     gGraphicsClient;
  150.  
  151.  
  152. //
  153. //    The variables from this gxPoint on, were added to support QuickDraw™ GX.
  154. //
  155.  
  156. //
  157. //    gthePage contain all of the GX shapes which are displayed in the window. gthePage is defined
  158. //    as a gxPictureType in the function CreateShapes. CreateShapes creates all of the shapes
  159. //    contained in gthePage.
  160. // 
  161. gxShape                gthePage;
  162.  
  163. //
  164. //    This viewPort is the child attached to the window's parent viewPort. Since it is a child viewPort,
  165. //    we (the application) need to maintain the clip shape. We also have the ability to manipulate this
  166. //    ViewPort as we see fit, therefore we adjust the mapping, to reflect scrolling changes by the user.
  167. //
  168. gxViewPort            gcontentViewPort;
  169.  
  170.  
  171. // 
  172. //    If gDebugging = TRUE, graphics library errors and notices will be posted.  This functionality  will only work with 
  173. //    the "debugging" version of the QuickDraw init.  If this version of the init is not installed, nothing bad will happen, 
  174. //    but these  functions will not work.
  175. //
  176. Boolean                gDebugging = true;
  177.  
  178. //
  179. //  Set gGiveMeValidation = TRUE, if you will receive run-time validation. 
  180. //
  181. Boolean                gGiveMeValidation = true;
  182.  
  183.  
  184. //     
  185. //    gGraphicsHeapSize sets the size of the graphics gxHeap created by calling the GXNewGraphicsClient routine
  186. //    in main () within graphics shell.c.  You can determine the amount of graphics gxHeap required by using GraphicsBug.
  187. //    With  gGraphicsHeapSize set to 25k, I had 2 free blocks left in the graphics gxHeap. Sounds good to me.
  188. //
  189. long            gGraphicsHeapSize = 25;
  190.  
  191.  
  192.  
  193. /**----- main --------------------------------------------------------------------------------
  194.  --
  195.  --     Main initializes the application memory, toolbox, menubar, the GX world, and global 
  196.  --        variables. We also create a document & window containing our GX picture, which contains
  197.  --        all of our rectangles.
  198.  --
  199.  **/
  200. main()
  201. {
  202.     ToolBoxInit();
  203.     MenuBarInit();
  204.     QuickDrawGXInit();    //    This function initializes the GX system
  205.     PrintInit();
  206.  
  207.     gDone = false;            /* Initialize global variables */
  208.  
  209.     CreateDocumentWindow(nil, "\p QuickDraw GX Scrolling ");
  210.  
  211.     while (!gDone)
  212.         HandleEvent();
  213. }
  214.  
  215.  
  216. /**----- ToolBoxInit -------------------------------------------------------------------------
  217.  --
  218.  --        This function initializes the toolbox.
  219.  --
  220.  **/
  221. void ToolBoxInit(void)
  222. {
  223.     EventRecord    theEvent;
  224.     short        count;
  225.     
  226.     /**   Generic gxHeap initialization.  **/
  227.     MaxApplZone(); 
  228.     MoreMasters(); MoreMasters(); MoreMasters(); 
  229.     MoreMasters(); MoreMasters(); MoreMasters(); 
  230.  
  231.     InitGraf (&qd.thePort);
  232.     InitFonts ();
  233.     FlushEvents(everyEvent, 0);
  234.     InitWindows();
  235.     InitMenus();
  236.     TEInit();
  237.     InitDialogs(nil);
  238.     InitCursor();
  239.     
  240.     /* Multi-finder brings our application to the front after */
  241.     /* we ask for three events. */
  242.     for (count=3; count!=0; count--)
  243.         EventAvail(everyEvent, &theEvent);
  244. }
  245.  
  246.  
  247. /**----- MenuBarInit -------------------------------------------------------------------------
  248.  --
  249.  --     This function initializes the menus, and installs DAs in the Apple Menu.
  250.  --
  251.  **/
  252. void MenuBarInit(void)
  253. {
  254.     Handle        theMenuBar;
  255.     MenuHandle    appleMenu;
  256.     
  257.     /* Install menus from resources */
  258.     theMenuBar = GetNewMBar(rMenuBar);
  259.     if (theMenuBar == nil)
  260.         ErrorAlert(kNoMenuBarErr, true);
  261.     SetMenuBar(theMenuBar);
  262.     DisposHandle(theMenuBar);
  263.     
  264.     /* Add desk accessories to Apple Menu */
  265.     appleMenu = GetMHandle(mApple);
  266.     if (appleMenu != nil)
  267.         AddResMenu(appleMenu, kDriverType);
  268.  
  269.     DrawMenuBar();
  270. }
  271.  
  272.  
  273.  
  274. /**----- QuickDrawGXInit ---------------------------------------------------------------------
  275.  --
  276.  --        This function makes all of the calls required to gxInitialize the GX system, except 
  277.  --        for the printing part. For complete details regarding each call made, please see
  278.  --        the comment blocks.                                                    (GX Addition)
  279.  --                                                 
  280.  **/
  281. void QuickDrawGXInit(void)
  282. {
  283.     //     
  284.     //    The GXNewGraphicsClient routine defines the graphics gxHeap size. If you do not make this call, 
  285.     //    the GX graphics engine will create this gxHeap automatically. How? It will create a graphics
  286.     //    gxHeap of 600k. This call allows you to explicity define the ammount of memory used by the 
  287.     //  graphics system to store it's graphics objects gxHeap.
  288.     //
  289.     //    If you do not pass a value for gGraphicsHeapSize, you will receive the default graphics gxHeap.
  290.     //    The GX system will automatically page objects to disk when memory is low.
  291.     //
  292.     gGraphicsClient = GXNewGraphicsClient(nil, gGraphicsHeapSize * 1024, 0L);
  293.  
  294.  
  295.     // 
  296.     //    If gDebugging = TRUE, you will receive graphics library errors & notices will be posted.  This
  297.     //    functionality will only work with the "debugging" version of the Secret Graphics init.  If this
  298.     //    init is not installed, these functions will not work. The "debugging" version of the Secret 
  299.     //    Graphics init is approximately 810K.
  300.     //
  301.     if (gDebugging) {
  302.         SetGraphicsLibraryErrors ();
  303.         SetGraphicsLibraryNotices();    
  304.     }
  305.  
  306.  
  307.     // 
  308.     //    Set  "gGiveMeValidation" to TRUE, if you want run-time validation. As you increase the amount
  309.     //    of validation, The drawing speed will SLOW down due to all of the internal checking. 
  310.     //    
  311.     //    gxPublicValidation will check parameters to public routines. For additional details regarding 
  312.     //    the various levels of validation, please see the documentation.
  313.     //
  314.     if (gGiveMeValidation) GXSetValidation(gxPublicValidation); 
  315.  
  316.  
  317.     //
  318.     //  Create the default data structures.
  319.     //
  320.     GXEnterGraphics();
  321.  
  322.  
  323.     //
  324.     //    Initialize the common colors library defined in "gxColor library.c" and "graphics library.h".
  325.     //    This library is a simple method available for you to gxColor an object quickly by calling the
  326.     //    the SetShapeCommonColor(...) function.
  327.     //
  328.      InitCommonColors();
  329. }
  330.  
  331.  
  332.  
  333. /**----- PrintInit ---------------------------------------------------------------------------
  334.  --
  335.  --        This function will someday gxInitialize the GX Print Manager, if it is present.
  336.  --
  337.  **/
  338. void PrintInit(void)
  339. {
  340.  
  341. }
  342.  
  343.  
  344.  
  345. /**----- HandleEvent -------------------------------------------------------------------------
  346.  --
  347.  --        This function contains the main event loop.
  348.  --
  349.  **/
  350. void HandleEvent(void)
  351. {
  352.     EventRecord    theEvent;
  353.     OSErr        myErr;
  354.     WindowPtr    theWindow;
  355.     
  356.     WaitNextEvent(everyEvent, &theEvent, 30, nil);
  357.  
  358.     switch (theEvent.what)
  359.     {
  360.     case mouseDown:
  361.         HandleMouseDown(&theEvent);
  362.         break;
  363.     
  364.     case keyDown:
  365.     case autoKey:
  366.         HandleKeyPress(&theEvent);
  367.         break;
  368.     
  369.     case updateEvt:
  370.         theWindow = (WindowPtr)theEvent.message;
  371.         BeginUpdate(theWindow);
  372.         if (!EmptyRgn(theWindow->visRgn))
  373.         {
  374.             SetPort(theWindow);
  375.             UpdtControl(theWindow, theWindow->visRgn);
  376.             DrawGrowIcon(theWindow);
  377.             DrawWindow(theWindow);
  378.         }
  379.         EndUpdate(theWindow);
  380.     
  381.     case diskEvt:
  382.         HandleDiskEvent(&theEvent);
  383.         break;
  384.  
  385.     case activateEvt:
  386.         ActivateWindow((WindowPtr)theEvent.message, theEvent.modifiers & activeFlag);
  387.         break;
  388.     
  389.     case osEvt:
  390.         HandleOSEvent(&theEvent);
  391.         break;
  392.     
  393.     case kHighLevelEvent:
  394.         myErr = AEProcessAppleEvent(&theEvent);
  395.         if  (myErr != noErr)
  396.         {
  397.             ErrorAlert(kAppleEventErr, false);
  398.         }
  399.         break;
  400.     }
  401. }
  402.  
  403.  
  404. /**----- HandleMouseDown ---------------------------------------------------------------------
  405.  --
  406.  --        This functions is called whenever the mouse button is pressed. It finds the mouse 
  407.  --        location when the button was pressed and routes the event appropriately.
  408.  --
  409.  **/
  410. void HandleMouseDown(EventRecord *theEvent)
  411. {
  412.     short            thePart;
  413.     WindowPtr        theWindow;
  414.     Rect            theRect;
  415.     short            controlPart;
  416.     ControlHandle    theControl;
  417.  
  418.     thePart = FindWindow(theEvent->where, &theWindow);
  419.     switch (thePart)
  420.     {
  421.     case inMenuBar:
  422.         AdjustMenus();
  423.         DoMenu(MenuSelect(theEvent->where));
  424.         break;
  425.     
  426.     case inSysWindow:
  427.         SystemClick(theEvent, theWindow);
  428.         break;
  429.     
  430.     case inContent:
  431.         if (theWindow != FrontWindow())
  432.             SelectWindow(theWindow);
  433.         else
  434.         {
  435.             SetPort(theWindow);
  436.             GlobalToLocal(&theEvent->where);
  437.             controlPart = FindControl(theEvent->where, theWindow, &theControl);
  438.             if (controlPart != 0)
  439.                 DoControl(theEvent->where, theControl, controlPart);
  440.         }
  441.         break;
  442.  
  443.     case inDrag:
  444.         if (theWindow != FrontWindow())
  445.             SelectWindow(theWindow);
  446.         theRect = (**GetGrayRgn()).rgnBBox;
  447.         DragWindow(theWindow, theEvent->where, &theRect);
  448.         break;
  449.     
  450.     case inGrow:
  451.         DoGrowWindow(theWindow, theEvent->where);
  452.         break;
  453.  
  454.     case inGoAway:
  455.         if (TrackGoAway(theWindow, theEvent->where))
  456.           ShutdownProgram();
  457.         break;
  458.     
  459.     case inZoomIn:
  460.     case inZoomOut:
  461.         if (TrackBox(theWindow, theEvent->where, thePart))
  462.             DoZoomWindow(theWindow, thePart);
  463.         break;
  464.     }
  465. }
  466.  
  467.  
  468.  
  469. /**----- ResetContentViewPortClip ------------------------------------------------------------
  470.  --
  471.  --        This function resets the clip gxShape of the "gcontentViewPort", to represent the new
  472.  --        clip gxShape after the user has zoomed or resized the window.           (GX Scrolling)
  473.  --
  474.  **/
  475. void ResetContentViewPortClip (WindowPtr theWindow)
  476. {
  477.     gxRectangle    viewRect;
  478.     gxShape        contentViewPortClipShape;
  479.  
  480.     //
  481.     //    Return a fixed gxPoint gxRectangle in "viewRect" which represents the portRect of the
  482.      //    window. This gxShape will be used as the new clip gxShape for "gcontentViewPort".
  483.     GetWindowBoundsShape(theWindow, &viewRect);
  484.  
  485.     //
  486.     // Adjust our viewRect to accommodate the scroll bars
  487.     //
  488.     viewRect.right -= ff(kScrollBarWidth - 1);    
  489.     viewRect.bottom -= ff(kScrollBarWidth - 1);
  490.  
  491.     //
  492.     //    Create and set the new clip gxShape.
  493.     //
  494.     contentViewPortClipShape = GXNewRectangle(&viewRect);
  495.     GXSetViewPortClip(gcontentViewPort, contentViewPortClipShape);
  496.  
  497.     GXDisposeShape (contentViewPortClipShape);
  498. }
  499.  
  500.  
  501.  
  502. /**----- DoGrowWindow ------------------------------------------------------------------------
  503.  --
  504.  --        This function takes care of growing a window after the mouse has been pressed over
  505.  --        the grow icon.  It allows maximum growth of the document size or display size, whichever
  506.  --        is smaller. It allows minimum growth to (kMinWindowWidth,kMinWindowHeight) or the 
  507.  --        document size, whichever is larger. Finally, it adjusts and redraws the scroll bars 
  508.  --        for the new window size.
  509.  --
  510.  **/
  511. void DoGrowWindow(WindowPtr theWindow, Point where)
  512. {
  513.     Rect        growRect, windRect;
  514.     Rect        thePage;
  515.     short        width, height;
  516.     long        newSize;
  517.     Point        origin;
  518.  
  519.     thePage = ((MyWindowPeek)theWindow)->documentBoundsRect;
  520.  
  521.     width = thePage.right - thePage.left + kScrollBarWidth;
  522.     height = thePage.bottom - thePage.top + kScrollBarWidth;
  523.  
  524.     growRect = (**GetGrayRgn()).rgnBBox;
  525.     if (theWindow->portRect.left + width < growRect.right)
  526.        growRect.right = theWindow->portRect.left + width;
  527.         
  528.     if (theWindow->portRect.top + height < growRect.bottom)
  529.          growRect.bottom = theWindow->portRect.top + height;
  530.  
  531.     // Minimum size is (kMinWindowWidth,kMinWindowHeight) 
  532.     growRect.left = kMinWindowWidth;
  533.     growRect.top = kMinWindowHeight;
  534.     
  535.     // Make sure maximum size is at least minimum size
  536.     if (growRect.right < growRect.left) growRect.right = growRect.left;
  537.     if (growRect.bottom < growRect.top) growRect.bottom = growRect.top;
  538.  
  539.     /* Allow user to grow the window, then resize it */
  540.     newSize = GrowWindow(theWindow, where, &growRect);
  541.     
  542.     if (newSize != 0)
  543.     {
  544.         GrafPtr        saveport;
  545.  
  546.         InvalidateScrollBars(theWindow);
  547.         SizeWindow(theWindow, LoWord(newSize), HiWord(newSize), true);
  548.         InvalidateScrollBars(theWindow);
  549.         ResizeScrollBars(theWindow);
  550.  
  551.         // 
  552.         //    The user as grown the window, we need to update the clip gxShape of the contentviewPort
  553.         //    we attached to the window earlier in the CreateDocumentWindow function. If we did not
  554.         //    update the clip gxShape of the contentviewPort clip, we would draw through the scroll  
  555.         //    bars on the next update event.                                           (GX Scrolling)
  556.         //
  557.         ResetContentViewPortClip(theWindow);
  558.  
  559.         
  560.         /* reposition document */
  561.         origin = ((MyWindowPeek)theWindow)->origin;
  562.         width = theWindow->portRect.right - theWindow->portRect.left - origin.h - width + 1;
  563.         height = theWindow->portRect.bottom - theWindow->portRect.top - origin.v - height + 1;
  564.         if (width < 0) width = 0;
  565.         if (height < 0) height = 0;
  566.  
  567.         if ( (width > 0) || (height > 0) )
  568.         {
  569.             DoScroll(theWindow, width, height);
  570.             ResizeScrollBars(theWindow);
  571.         }
  572.     }
  573. }
  574.  
  575.  
  576. /**----- DoZoomWindow ------------------------------------------------------------------------
  577.  --
  578.  --        This function zooms a window. It follows the new human interface guidelines be 
  579.  --        dealing with multiple displays. To do this, every time the window is zoomed to the 
  580.  --        standard state, it recalculates the standard state based on the display that contains
  581.  --        the largest area of the window. This routine   was adapted from Macintosh Technical 
  582.  --        Note #79: "_ZoomWindow".
  583.  --
  584.  **/
  585. void DoZoomWindow(WindowPtr theWindow, short thePart)
  586. {
  587.     Rect                deviceRect, zoomRect;
  588.     Point                offset;
  589.     WStateDataHandle    windowState;
  590.         
  591.     SetPort(theWindow);
  592.     EraseRect(&theWindow->portRect);
  593.     if ( (thePart == inZoomOut) && (ColorQDAvail()) )
  594.     {
  595.         /* Get window location in global coordinates */
  596.         SetPt(&offset, 0, 0);
  597.         LocalToGlobal(&offset);
  598.         
  599.         deviceRect = GetDeviceRect(theWindow);
  600.  
  601.         zoomRect = ((MyWindowPeek)theWindow)->documentBoundsRect;
  602.         zoomRect.right += kScrollBarWidth-1;
  603.         zoomRect.bottom += kScrollBarWidth-1;
  604.  
  605.         OffsetRect(&zoomRect, -zoomRect.left, -zoomRect.top);    /* Adjust upper left to 0,0 */
  606.  
  607.         /* At least minimum window size */
  608.         if (zoomRect.right < kMinWindowWidth-1) zoomRect.right = kMinWindowWidth-1;
  609.         if (zoomRect.bottom < kMinWindowHeight-1) zoomRect.bottom = kMinWindowHeight-1;
  610.  
  611.         OffsetRect(&zoomRect, offset.h, offset.v);                /* Align to window */
  612.         
  613.         FitWindowOnDevice(&zoomRect, &deviceRect);
  614.  
  615.         windowState = (WStateDataHandle)((WindowPeek)theWindow)->dataHandle;
  616.         (**windowState).stdState = zoomRect;
  617.     }
  618.     ZoomWindow(theWindow, thePart, true);
  619.     InvalRect(&theWindow->portRect);
  620.  
  621.     ResizeScrollBars(theWindow);
  622.  
  623.     // 
  624.     //    The user as grown the window, we need to update the "gcontentviewPort" we attached to 
  625.     //    the window earlier in the CreateDocumentWindow (..) function. If we did not update, the
  626.     //    contentviewPort clip, we would draw through the scroll bars on the next update event. 
  627.     //                                                                            (GX Scrolling)
  628.     //
  629.     ResetContentViewPortClip(theWindow);
  630. }
  631.  
  632.  
  633.  
  634. /**----- FitWindowOnDevice -------------------------------------------------------------------
  635.  --
  636.  --        This routine takes two rectangles as parameters. windRect is the location of the 
  637.  --        window in global coordinates. deviceRect is the boundary of the device in global 
  638.  --        coordinates. This routine fits windRect inside deviceRect.  windRect is  modified, 
  639.  --        and upon completion, is where the window should be positioned.
  640.  --
  641.  --        Here's how the algorithm works:
  642.  --        Attempt to leave the window in the same location.  If the window doesn't fit inside
  643.  --        the deviceRect, move it to the upper left corner of deviceRect.  If the window still 
  644.  --        doesn't fit, resize windRect to fit inside the maxRect.
  645.  --
  646.  --        NOTE: Both rectangles must be in the same coordinate system.
  647.  --
  648.  **/
  649. void FitWindowOnDevice(Rect *windRect, Rect *deviceRect)
  650. {
  651.     Rect    theUnion;    
  652.  
  653.     UnionRect(windRect, deviceRect, &theUnion);
  654.     if (!EqualRect(deviceRect, &theUnion))            /* window contained on screen? */
  655.     {                                                /* no, move to upper left corner of maxRect */
  656.         OffsetRect(windRect, deviceRect->left-windRect->left, deviceRect->top-windRect->top);
  657.         UnionRect(windRect, deviceRect, &theUnion);
  658.         if (!EqualRect(deviceRect, &theUnion))        /* window contained on screen? */
  659.         {                                            /* no, resize window to fit */
  660.             if (windRect->right > deviceRect->right)
  661.                 windRect->right = deviceRect->right;
  662.             if (windRect->bottom > deviceRect->bottom)
  663.                 windRect->bottom = deviceRect->bottom;
  664.         }
  665.     }
  666. }
  667.  
  668.  
  669. /**----- GetDeviceRect -----------------------------------------------------------------------
  670.  --
  671.  --        This routine takes a WindowPtr as its parameter. It returns the boundary gxRectangle of
  672.  --        the device that contains the largest area of that window. The rect is returned in 
  673.  --        global coordinates.
  674.  --
  675.  **/
  676. Rect GetDeviceRect(WindowPtr theWindow)
  677. {
  678.     Rect        deviceRect, windRect, theSect;
  679.     GDHandle    nthDevice, dominantGDevice;
  680.     long        sectArea, greatestArea;
  681.     short        bias;
  682.     Point        offset;
  683.     
  684.     /* Get portRect in global coordinates */
  685.     windRect = theWindow->portRect;
  686.     SetPt(&offset, 0, 0);
  687.     LocalToGlobal(&offset);
  688.     OffsetRect(&windRect, offset.h, offset.v);
  689.  
  690.     bias = kTitleBarHeight;
  691.     windRect.top -= bias;
  692.     
  693.     /* This loop checks the window against all the gdRects in the gDevice list */
  694.     /* and remembers which gdRect contains the largest portion of the window   */
  695.     /* being zoomed. */
  696.     nthDevice = GetDeviceList();
  697.     greatestArea = 0;
  698.     while (nthDevice != nil)
  699.     {
  700.         if (TestDeviceAttribute(nthDevice, screenDevice))
  701.             if (TestDeviceAttribute(nthDevice, screenActive))
  702.             {
  703.                 SectRect(&windRect, &(**nthDevice).gdRect, &theSect);
  704.                 sectArea = (long)(theSect.right - theSect.left) *
  705.                                  (theSect.bottom - theSect.top);
  706.                 if (sectArea > greatestArea)
  707.                 {
  708.                     greatestArea = sectArea;
  709.                     dominantGDevice = nthDevice;
  710.                 }
  711.             }
  712.         nthDevice = GetNextDevice(nthDevice);
  713.     }
  714.  
  715.     /* Create a max zoom gxRectangle, accounting for menu bar height if on main screen */
  716.     if (dominantGDevice == GetMainDevice())
  717.         bias += GetMBarHeight();
  718.     SetRect(&deviceRect, (**dominantGDevice).gdRect.left+3,
  719.             (**dominantGDevice).gdRect.top+bias+3,
  720.             (**dominantGDevice).gdRect.right-3,
  721.             (**dominantGDevice).gdRect.bottom-3);
  722.     
  723.     return(deviceRect);
  724. }
  725.  
  726.  
  727. /**----- HandleKeyPress ----------------------------------------------------------------------
  728.  --
  729.  --        This function is called whenever a key is pressed. Since this program has no typed 
  730.  --        input, we are only concerned about command key equivalent menu selections.
  731.  --
  732.  **/
  733. void HandleKeyPress(EventRecord *theEvent)
  734. {
  735.     char        theChar;
  736.  
  737.     theChar = theEvent->message & charCodeMask;
  738.     if ((theEvent->modifiers & cmdKey)!=0)
  739.     {
  740.         AdjustMenus();
  741.         DoMenu(MenuKey(theChar));
  742.     }
  743. }
  744.  
  745.  
  746.  
  747. /**----- HandleDiskEvent ---------------------------------------------------------------------
  748.  --
  749.  --        This function checks whether the disk was successfully mounted. If it wasn't, the disk
  750.  --        initialization package is invoked.
  751.  --
  752.  **/
  753. void HandleDiskEvent(EventRecord *event)
  754. {
  755.     Point thePoint = {120, 120};
  756.     
  757.     if (HiWord(event->message) != noErr)
  758.     {
  759.         DILoad();
  760.         DIBadMount(thePoint, event->message);    /* thePoint is ignored in sys 7+ */
  761.         DIUnload();
  762.     }
  763. }
  764.  
  765.  
  766. /**----- HandleOSEvent -----------------------------------------------------------------------
  767.  --
  768.  --        This function is called when OSEvents are received. It handles suspend, resume, and mouse 
  769.  --        moved OSEvents.
  770.  --
  771.  **/
  772. void HandleOSEvent(EventRecord *theEvent)
  773. {
  774.     WindowPtr    theWindow;
  775.     
  776.     switch ((theEvent->message >> 24) & 0x000000ff)
  777.     {
  778.     case suspendResumeMessage:
  779.         if (theEvent->message & 0x00000001)        /* resume message */
  780.         {
  781.             SetCursor(&qd.arrow);
  782.             theWindow = FrontWindow();
  783.             if (theWindow != nil)
  784.                 ActivateWindow(theWindow, true);    /* Activate front window */
  785.             /* Copy contents of clipboard (if changed) to private scrap */
  786.         }
  787.         else    /* suspend message */
  788.         {
  789.             theWindow = FrontWindow();
  790.             if (theWindow != nil)
  791.                 ActivateWindow(theWindow, false);    /* Deactivate front window */
  792.             /* Move private scrap to clipboard */
  793.         }
  794.         break;
  795.     
  796.     case mouseMovedMessage:
  797.         break;
  798.     }
  799. }
  800.  
  801.  
  802. /**----- ActivateWindow ----------------------------------------------------------------------
  803.  --
  804.  --        This function activates or deactivates a window, and is called when either an 
  805.  --        activate/deactivate event or suspend/resume event is received. The parameters are a 
  806.  --        window pointer to the desired window, and a gxBoolean specifying whether to activate
  807.  --        or deactivate the window.
  808.  **/
  809. void ActivateWindow(WindowPtr theWindow, Boolean activate)
  810. {
  811.     if (theWindow == nil)    /* safety check */
  812.         return;
  813.  
  814.     if (activate)        /* activiate window */
  815.     {
  816.         /* Highlight controls */
  817.         DrawGrowIcon(theWindow);
  818.         HiliteControl(((MyWindowPeek)theWindow)->vScrollBar, 0);
  819.         HiliteControl(((MyWindowPeek)theWindow)->hScrollBar, 0);
  820.         /* Restore vertical bar or highlighting */
  821.         /* Enable appropriate menu items */
  822.     }
  823.     else    /* deactivate window */
  824.     {
  825.         /* Unhighlight controls */
  826.         DrawGrowIcon(theWindow);
  827.         HiliteControl(((MyWindowPeek)theWindow)->vScrollBar, 255);
  828.         HiliteControl(((MyWindowPeek)theWindow)->hScrollBar, 255);
  829.         /* Remove vertical bar or highlighting */
  830.         /* Disable appropriate menu items */
  831.     }
  832. }
  833.  
  834.  
  835.  
  836. /**----- DoMenu ------------------------------------------------------------------------------
  837.  --
  838.  --        This function is called when a menu item has been selected either with the mouse, 
  839.  --        or a keyboard equivalent.
  840.  --
  841.  **/
  842. void DoMenu(long menuChoice)
  843. {
  844.     short            theMenu;
  845.     short            theItem;
  846.     MenuHandle        appleMenu;
  847.     Str255            accName;
  848.     GrafPtr            savePort;
  849.  
  850.     theMenu = HiWord(menuChoice);
  851.     theItem = LoWord(menuChoice);
  852.     switch (theMenu)
  853.     {
  854.     case mApple:
  855.         if (theItem == iAbout)
  856.             Alert(rAboutBox, (ModalFilterProcPtr)nil);
  857.         else
  858.         {
  859.             appleMenu = GetMHandle(mApple);
  860.             if (appleMenu != nil)
  861.             {
  862.                 GetItem(appleMenu, theItem, accName);    /* Call desk accessory */
  863.                 GetPort(&savePort);
  864.                 OpenDeskAcc(accName);
  865.                 SetPort(savePort);
  866.             }
  867.         }
  868.         break;
  869.         
  870.     case mFile:
  871.         switch (theItem)
  872.         {
  873.         case iOpen:
  874.             DoOpenCommand();
  875.             break;
  876.         
  877.         case iClose:
  878.             CloseFrontWindow();
  879.             break;
  880.         
  881.         case iPageSetup:
  882.             break;
  883.         
  884.         case iPrint:
  885.             DoPrintCommand();
  886.             break;
  887.         
  888.         case iQuit:
  889.             ShutdownProgram();
  890.             break;
  891.         }
  892.         break;
  893.     }
  894.     HiliteMenu(0);
  895. }
  896.  
  897.  
  898.  
  899. void DoOpenCommand(void)
  900. {
  901. }
  902.  
  903.  
  904. void DoPrintCommand(void)
  905. {
  906. }
  907.  
  908.  
  909.  
  910. void PrintDocument(PicHandle thePicture)
  911. {
  912.  
  913. }
  914.  
  915.  
  916. PicHandle ReadDocument(FSSpecPtr mySpec)
  917. {
  918.  
  919. }
  920.  
  921.  
  922.  
  923. /**----- GetWindowBoundsShape ----------------------------------------------------------------
  924.  --
  925.  --        This function returns a fixed gxPoint gxRectangle which represents the portRect of the
  926.  --        window. The gxShape returned is used as the new clip gxShape for the gcontentViewPort.
  927.  --                                                                            (GX Scrolling) 
  928.  **/
  929. void GetWindowBoundsShape(WindowPtr myWindow, gxRectangle *boundingBoxPtr)
  930. {
  931.     GrafPtr                oldPort;
  932.     Rect                qdBounds;
  933.     gxRectangle            gxBounds;
  934.     gxValidationLevel     currentValidation;
  935.  
  936.     GetPort(&oldPort);
  937.     SetPort(myWindow);
  938.  
  939.     qdBounds = myWindow->portRect;        // this is in globals coordinates
  940.  
  941.      //
  942.      //    Unfortunately, GXConvertQDPoint(..) will not survive validation with the QD GX ß2
  943.      //    seed. Therefore, we get the validation level set up by the application,  and turn the
  944.      //    validation off. We will reset the validation to it's original setting below.
  945.      //
  946.      //    This problem has already been fixed in the QD GX ß3 build, therefore this work around 
  947.      //    will be removed at ß3. Details about the parameters for the GXConvertQDPoint (..) call
  948.      //    can be found in the QD GX ß2 Graphics Notes within the "• Open Me First •" folder.
  949.      // 
  950.     currentValidation = GXGetValidation();
  951.       if (currentValidation) GXSetValidation(gxNoValidation);
  952.      
  953.     //
  954.     //  Convert the global Quickdraw coordinates to local fixed coordinates. 
  955.     //
  956.     GXConvertQDPoint((Point *) &qdBounds.top, 0, (gxPoint *) &gxBounds.left);
  957.     GXConvertQDPoint((Point *) &qdBounds.bottom, 0, (gxPoint *) &gxBounds.right);
  958.  
  959.     //
  960.     //    Reset the validation to the original setting.
  961.     //
  962.        if (currentValidation) GXSetValidation(currentValidation);
  963.  
  964.     *boundingBoxPtr = gxBounds;
  965.  
  966.     SetPort(oldPort);
  967. }
  968.  
  969.  
  970.  
  971. /**----- CreateThePageOfGXShapes -------------------------------------------------------------
  972.  --
  973.  --        This function creates a GX picture containing the shapes which will be displayed
  974.  --        within our window. In this case, all of the shapes will be rectangles
  975.  --                                                                         (GX Addition)
  976.  **/
  977. gxShape CreateThePageOfGXShapes (gxShape thePage)
  978. {
  979.     gxShape        tempRectangleShape;
  980.      gxRectangle     rectangleGeometry = {0, 0, ff(100), ff(100)};    
  981.     short        loop;
  982.     
  983.     //
  984.     //    If the picture passed in has not been created, create an empty GX picture. We set
  985.     //    the "gxUniqueItemsShape" attribute because we are adding the same gxRectangle multiple
  986.     //    times. This guarantees that each rectagnle will have a "unique" reference within
  987.     //    the picture. Otherwise, you would only see the last gxRectangle added to the picture.
  988.     //
  989.     if (thePage == nil) 
  990.     {
  991.         thePage = GXNewShape(gxPictureType);
  992.         GXSetShapeAttributes(thePage, gxUniqueItemsShape);
  993.     }
  994.     
  995.     //
  996.     //    Create a gxRectangle: rotated 45 degrees, with a close frame fill, and a pen width of 4.
  997.     //
  998.     tempRectangleShape = GXNewRectangle(&rectangleGeometry); 
  999.     GXRotateShape(tempRectangleShape, ff(45), ff(50), ff(50));
  1000.     GXSetShapeFill(tempRectangleShape, gxClosedFrameFill);
  1001.     GXSetShapePen(tempRectangleShape, ff(4));
  1002.     GXMoveShape(tempRectangleShape, ff(35), ff(35));
  1003.  
  1004.     //
  1005.     //    Set the gxColor of the gxRectangle by calling SetShapeCommonColor (..), and add the 
  1006.     //    gxRectangle to our picture.
  1007.     //
  1008.     for (loop =1; loop <= 11; loop++)
  1009.     {
  1010.         SetShapeCommonColor (tempRectangleShape, loop + 5);
  1011.         AddToShape(thePage, tempRectangleShape);
  1012.         GXMoveShape(tempRectangleShape, ff(60), ff(105));
  1013.     }
  1014.  
  1015.     GXDisposeShape (tempRectangleShape);
  1016.     
  1017.     return (thePage);
  1018. }
  1019.     
  1020.  
  1021. /**----- CreateDocumentWindow ----------------------------------------------------------------
  1022.  --
  1023.  --        This function creates a new document window.  We attached a parent gxViewPort to the 
  1024.  --        window and a child gxViewPort to it. Having the application maintain the child gxViewPort's
  1025.  --        clip gxShape and gxMapping will allow use to draw within the scroll bars & update it's
  1026.  --        gxMapping to reflect scrolling of the shapes.
  1027.  --
  1028.  --        The parameters: we ignore the PicHandle at this gxPoint and the str63 containing the 
  1029.  --        name for the title bar of the window is used.
  1030.  --
  1031.  --        A gxBoolean is returned indicating success.  Failure may result from an running out of 
  1032.  --        memory in the gxHeap.
  1033.  --
  1034.  **/
  1035. Boolean CreateDocumentWindow(PicHandle thePicture, Str63 name)
  1036. {
  1037.     WindowPtr        theWindow;
  1038.     ControlHandle    hControl, vControl;
  1039.     Rect            controlRect, deviceRect, windRect, docRect = {0, 0, 1000, 1000};
  1040.     Point            origin;
  1041.  
  1042.     /* Allocate space for window */
  1043.     theWindow = (WindowPtr)NewPtr(sizeof(MyWindowRecord));
  1044.     if (theWindow == nil)
  1045.     {
  1046.         ErrorAlert(kOutOfMemoryErr, false);
  1047.         return(false);
  1048.     }
  1049.     GetNewWindow(rDocumentWindow, theWindow, (WindowPtr)-1);
  1050.  
  1051.     ((MyWindowPeek)theWindow)->documentBoundsRect = docRect;
  1052.     SetPt(&((MyWindowPeek)theWindow)->origin, 0, 0);
  1053.     SetWTitle(theWindow, name);
  1054.  
  1055.     windRect = ((MyWindowPeek)theWindow)->documentBoundsRect;
  1056.  
  1057.     windRect.right += kScrollBarWidth-1;
  1058.     windRect.bottom += kScrollBarWidth-1;
  1059.     OffsetRect(&windRect, -windRect.left, -windRect.top);    /* Adjust upper left to 0,0 */
  1060.     if (windRect.right < kMinWindowWidth-1) windRect.right = kMinWindowWidth-1;
  1061.     if (windRect.bottom < kMinWindowHeight-1) windRect.bottom = kMinWindowHeight-1;
  1062.  
  1063.     /* Allocate space for HORIZONTAL scroll bar */
  1064.     SetRect(&controlRect, 0, 0, 100, 10);
  1065.     hControl = NewControl(theWindow, &controlRect, "\p", false, 0, 0, 0, scrollBarProc, 0);
  1066.     ((MyWindowPeek)theWindow)->hScrollBar = hControl;
  1067.     if (hControl == nil)
  1068.     {
  1069.         CloseWindow(theWindow);
  1070.         DisposePtr((Ptr)theWindow);
  1071.         ErrorAlert(kOutOfMemoryErr, false);
  1072.         return(false);
  1073.     }
  1074.     
  1075.     /* Allocate space for VERTICAL scroll bar */
  1076.     SetRect(&controlRect, 0, 0, 10, 100);
  1077.     vControl = NewControl(theWindow, &controlRect, "\p", false, 0, 0, 0, scrollBarProc, 0);
  1078.     ((MyWindowPeek)theWindow)->vScrollBar = vControl;
  1079.     if (vControl == nil)
  1080.     {
  1081.         DisposeControl(hControl);
  1082.         CloseWindow(theWindow);
  1083.         DisposePtr((Ptr)theWindow);
  1084.         ErrorAlert(kOutOfMemoryErr, false);
  1085.         return(false);
  1086.     }
  1087.  
  1088.     /* POSITION the new window */
  1089.     if (FrontWindow() == nil)        /* no windows open, use default position */
  1090.     {                                /* Align to upper left of main device */
  1091.         OffsetRect(&windRect, 2, 2 + kTitleBarHeight+GetMBarHeight());
  1092.         deviceRect = qd.screenBits.bounds;
  1093.         deviceRect.left += 3;
  1094.         deviceRect.top += 3+GetMBarHeight()+kTitleBarHeight;
  1095.         deviceRect.right -= 3;
  1096.         deviceRect.bottom -= 3;
  1097.     }
  1098.     else    /* Position down and right from frontmost window */
  1099.     {
  1100.         SetPort(FrontWindow());
  1101.         SetPt(&origin, 0, 0);
  1102.         LocalToGlobal(&origin);
  1103.         origin.h += kNewWindowOffset;
  1104.         origin.v += kNewWindowOffset;
  1105.         OffsetRect(&windRect, origin.h, origin.v);
  1106.         deviceRect = GetDeviceRect(FrontWindow());
  1107.     }
  1108.  
  1109.     /* Adjust size and position for display        */
  1110.     /* If not enough room for entire window:    */
  1111.     /* 1. Position in upper left                */
  1112.     /* 2. Resize to fit on screen                */
  1113.     FitWindowOnDevice(&windRect, &deviceRect);
  1114.     MoveWindow(theWindow, windRect.left, windRect.top, true);
  1115.     SizeWindow(theWindow, windRect.right-windRect.left,
  1116.                 windRect.bottom-windRect.top, false);
  1117.     
  1118.     ResizeScrollBars(theWindow);        /* Initialize Scroll Bars */
  1119.  
  1120.     ShowControl(hControl);
  1121.     ShowControl(vControl);
  1122.     ShowWindow(theWindow);
  1123.  
  1124.     //
  1125.     //    We need to attach a couple of viewPorts to the window to allow our
  1126.     //    GX shapes to be clipped and scrolled correctly.     (GX Scrolling)    
  1127.     //
  1128.     {
  1129.         gxRectangle    viewRect;
  1130.         gxViewPort    windowParentViewPort;
  1131.         gxShape        contentViewPortShape;
  1132.         
  1133.         //
  1134.         //    Get a rectangle shape which represents the portRect of the
  1135.         //    window. This shape will be used as the clip shape for the
  1136.         //    "gcontentViewPort". This gxViewPort will have all of our
  1137.         //    GX objects drawn to.
  1138.         //
  1139.         GetWindowBoundsShape(theWindow, &viewRect);
  1140.  
  1141.         //
  1142.         //     Adjust our viewRect to accommodate the scroll bars
  1143.         //
  1144.         viewRect.right -= ff(kScrollBarWidth - 1);    
  1145.         viewRect.bottom -= ff(kScrollBarWidth - 1);
  1146.  
  1147.         //
  1148.         //    Add a viewPort to the window. This will enable the
  1149.         //    user to move the window around and have our GX objects
  1150.         //    drawn into the window.
  1151.         //    
  1152.         windowParentViewPort = GXNewWindowViewPort(theWindow);
  1153.  
  1154.         //
  1155.         //    Create a second viewPort and attached it to the "parent"
  1156.         //    viewPort of our window. You cannot manipulate the parent
  1157.         //    viewPort attached to a window, but you can manipulate it's
  1158.         //    child. We will manipulate the clip and gxMapping of this viewPort
  1159.         //    when the user resizes the window or scrolls it's contents. Also, we
  1160.         //    need this child viewPort because we want to set the clip shape of the
  1161.         //    window to reside within the scroll bars, not on top of them, which would
  1162.         //    be the case if we only used the parent viewPort.
  1163.         // 
  1164.         gcontentViewPort = GXNewViewPort(GXGetViewPortViewGroup(windowParentViewPort));
  1165.          
  1166.         //
  1167.         //    Set up the shape, clip and, mapping of our "gcontentViewPort". We will
  1168.         //    then attached it to the "parent" viewPort of the window.
  1169.         //
  1170.         contentViewPortShape = GXNewRectangle(&viewRect);
  1171.         GXSetViewPortClip(gcontentViewPort, contentViewPortShape);
  1172.         GXSetViewPortMapping(gcontentViewPort, nil);
  1173.         GXSetViewPortParent(gcontentViewPort, windowParentViewPort);
  1174.         GXDisposeShape (contentViewPortShape);
  1175.  
  1176.         //
  1177.         //    By calling SetDefaultViewPort (..), all shapes we create will 
  1178.         //    be automatically drawn to "gcontentViewPort".
  1179.         // 
  1180.         GXIgnoreGraphicsNotice(transform_already_set);
  1181.         SetDefaultViewPort(gcontentViewPort);            
  1182.         GXPopGraphicsNotice();
  1183.     
  1184.         gthePage = CreateThePageOfGXShapes (nil);
  1185.     }
  1186.  
  1187.     return(true);
  1188. }
  1189.  
  1190.  
  1191. /**----- CloseFrontWindow --------------------------------------------------------------------
  1192.  --
  1193.  --        This function closes the frontmost window and disposes of the window record allocated
  1194.  --        on the gxHeap for it.
  1195.  --
  1196.  **/
  1197. void CloseFrontWindow(void)
  1198. {
  1199.     WindowPtr    theWindow;
  1200.     
  1201.     theWindow = FrontWindow();
  1202.     if (theWindow!=nil)
  1203.     {
  1204.         CloseWindow(theWindow);
  1205.         DisposePtr((Ptr)theWindow);
  1206.     }
  1207. }
  1208.  
  1209.  
  1210.  
  1211. /**----- DrawWindow --------------------------------------------------------------------------
  1212.  --
  1213.  --        This function draws the contents of the window without overwriting the scroll bars.
  1214.  --
  1215.  **/
  1216. void DrawWindow(WindowPtr theWindow)
  1217. {
  1218.     PicHandle    thePicture;
  1219.     Rect        tempRect;
  1220.     Point        origin;
  1221.     RgnHandle    saveClip;
  1222.  
  1223.     SetPort(theWindow);
  1224.  
  1225.     saveClip = NewRgn();        /* Remove scroll bar areas from clipRgn */
  1226.     GetClip(saveClip);
  1227.     tempRect = theWindow->portRect;
  1228.     tempRect.right -= (kScrollBarWidth-1);
  1229.     tempRect.bottom -= (kScrollBarWidth-1);
  1230.     ClipRect(&tempRect);
  1231.  
  1232.     SetClip(saveClip);            /* Restore clipRgn */
  1233.     DisposeRgn(saveClip);        
  1234.  
  1235.     //
  1236.     //    Draw the shapes contained within our GX picture gxShape - gthePage (GX Addition)
  1237.     // 
  1238.     GXDrawShape (gthePage);
  1239. }
  1240.  
  1241.  
  1242. /**----- AdjustMenus -------------------------------------------------------------------------
  1243.  --
  1244.  --        This function is called immediately before each time the user makes a menu selection.
  1245.  --        It enables/disables the appropriate menu items based on the current state of the 
  1246.  --        program. In version 1.0, we do not update the menus. We only support "quit".
  1247.  **/
  1248. void AdjustMenus(void)
  1249. {
  1250. }
  1251.  
  1252.  
  1253.  
  1254. /**----- FileRoutinesAvail -------------------------------------------------------------------
  1255.  --
  1256.  --        This function is used before calling FSSpec routines to see if they are available.
  1257.  --        Note that MPW 3.2 and THINK C 5.0 both include glue that let you use Gestalt even if
  1258.  --        it is not in ROM or in the System File. If you are not using one of these environments, 
  1259.  --        and you don't have Gestalt glue, you will need to use the TrapAvailable check (as shown
  1260.  --        in Inside Macintosh VI 3-8) to determine whether the Gestalt call exists before calling
  1261.  --         it.
  1262.  **/
  1263. Boolean FileRoutinesAvail(void)
  1264. {
  1265.     long    response;
  1266.     
  1267.     if (Gestalt(gestaltFSAttr, &response) == noErr)
  1268.         if ((response >> gestaltHasFSSpecCalls) & 0x00000001)
  1269.             if (Gestalt(gestaltStandardFileAttr, &response) == noErr)
  1270.                 if ((response >> gestaltStandardFile58) & 0x00000001)
  1271.                     return(true);
  1272.     return(false);
  1273. }
  1274.  
  1275.  
  1276.  
  1277. /**----- ColorQDAvail ------------------------------------------------------------------------
  1278.  --
  1279.  --        This function is used before calling Color QuickDraw routines to see if they are 
  1280.  --        available.  Note that MPW 3.2 and THINK C 5.0 both include glue that let you use
  1281.  --        Gestalt even if it is not in ROM or in the System File. If you are not using one of 
  1282.  --        these environments, and you don't have Gestalt glue, you will need to use the 
  1283.  --        TrapAvailable check (as shown in Inside Macintosh VI 3-8) to determine whether the
  1284.  --     Gestalt call exists before calling it.
  1285.  --
  1286.  **/
  1287. Boolean ColorQDAvail(void)
  1288. {
  1289.     long    response;
  1290.     
  1291.     if (Gestalt(gestaltQuickdrawVersion, &response) == noErr)
  1292.         if ((response & 0x0000ffff) >= gestalt8BitQD)
  1293.             return(true);
  1294.     return(false);
  1295. }
  1296.  
  1297.  
  1298.  
  1299. /**----- ErrorAlert --------------------------------------------------------------------------
  1300.  --
  1301.  --        This function displays an error message in an alert.  The error number corresponds
  1302.  --         to an error message in a 'str#' resource.  This message is displayed in a dialog box.
  1303.  --          The Boolean parameter is true for a fatal error, and will cause the program to 
  1304.  --        immediately terminate instead of returning.
  1305.  --
  1306.  **/
  1307. void ErrorAlert(short errNumber, Boolean fatal)
  1308. {
  1309.     Str255    errorString;
  1310.     
  1311.     GetIndString(errorString, rErrorStrings, errNumber);
  1312.         
  1313.     ParamText(errorString, "\p", "\p", "\p");
  1314.     if (fatal)
  1315.     {
  1316.         StopAlert(rFatalErrorAlert, nil);
  1317.         ExitToShell();
  1318.     }
  1319.     else
  1320.         NoteAlert(rNonFatalErrorAlert, nil);
  1321. }
  1322.  
  1323.  
  1324.  
  1325. /**----- ShutdownProgram ---------------------------------------------------------------------
  1326.  --
  1327.  --        This function is called before normal termination of the program.  It sets the event
  1328.  --        loop done variable to true, so the program will exit at the end of the event loop. We
  1329.  --        call CloseFrontWindow() to dispose of our window and data structure containing our
  1330.  --        document information.
  1331.  --
  1332.  --        If this program had editing capabilities, this is where the user would be asked if 
  1333.  --        he wanted to save any changed documents before quitting.
  1334.  --
  1335.  **/
  1336. void ShutdownProgram(void)
  1337. {
  1338.     WindowPtr    theWindow;
  1339.     
  1340.     gDone = true;
  1341.     
  1342.     //     
  1343.     //    If we created a GX picture which contains our window full of information, we wnat to
  1344.     //    dispose of it, by callling GXDisposeShape. We call DisposeCommonColor () because we 
  1345.     //    initialized the common colors library earlier in the QuickDrawGXInit function.
  1346.     //                                                                         (GX Addition)
  1347.     if (gthePage != nil) GXDisposeShape(gthePage);  
  1348.  
  1349.        DisposeCommonColors();
  1350.  
  1351.     //
  1352.     //    This function call will dispose of the data contained in the window.
  1353.     //
  1354.     CloseFrontWindow();
  1355.     
  1356.     //    
  1357.     //     Deallocate all of the default data and memory structures for the GX 
  1358.     //    graphics and layout system.                                            (GX Addition)
  1359.     //
  1360.     GXExitGraphics();        
  1361.     GXDisposeGraphicsClient(gGraphicsClient);
  1362. }
  1363.